/**
 * ABC290E原题
 * B题的加强版，N=2E5，需要线性算法
 * 对于任意一对元素，如果它们相等，则它们必然处在某些可能的子串中，且不用修改，
 * 考虑计算这样的情况有多少次
 * 假设是Si == Sj， ...i...j......
 * 则一共在min(i, N-j+1)个子串中处在对应位置，不用修改。
 * 此时仍然不能for每一对位置，还是超时
 * 再考虑同一个字母的多个相等位置，位置向量记作Pos，
 * 求一个后缀和 Suf[i] = SIGMA{Pos[i...n]}
 * for Pos数组中的每一个下标u：
 *     令v位置是其分界线，即v之前的Pos[v]都满足 N-Pos[v]+1 > Pos[u]
 *     则当前位置无需更改的对数一共是 (v - u) * Pos[u] + Suf[v + 1]
 *     如果 v < u，直接就是 Suf[u + 1]
 * O(N)可以完成
 */
#include <bits/stdc++.h>
using namespace std;

using llt = long long;

int N;
string S;
map<int, vector<int>> Pos;

llt proc(const vector<int> & vec){
    llt ans = 0;
    vector<llt> suf(vec.size() + 1, 0);
    int u = 0, v = vec.size() - 1;
    int n = vec.size() - 1;
    while(u < n){
        llt t = vec[u];
        while(v > u and N + 1 <= t + vec[v]) suf[v] = suf[v + 1] + N - vec[v] + 1, --v;
        if(v >= u) ans += (v - u) * t + suf[v + 1];
        else ans += suf[u + 1];
        ++u; 
    }
    return ans;
}

void work(){
    cin >> S;
    N = S.length();
    for(int i=0;i<N;++i) Pos[S[i]].emplace_back(i + 1);

    llt res = 0;
    for(llt i=1;i<=N;++i){
        res += (N + 1 - i) * (i / 2);
    }

    llt ans = 0;
    for(const auto & p : Pos){
        ans += proc(p.second);
    }
    cout << res - ans << endl;
    return;
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("z.txt", "r", stdin);
#endif
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    int nofkase = 1;
    // cin >> nofkase; 
    while(nofkase--) work();
    return 0;
}
